package chaincode

import (
	"encoding/json" // 包含用于 JSON 编解码的功能
	"fmt"           // 提供格式化输入输出的功能

	"github.com/hyperledger/fabric-contract-api-go/contractapi" // 引入 Hyperledger Fabric 的链码 API 包
)

// SmartContract 提供了管理用户的函数
type SmartContract struct {
	contractapi.Contract
}
 
// User 描述了简单用户的基本细节
// 按照字母顺序插入结构字段 => 以实现跨语言的确定性
// Go语言在转换为JSON时会保持顺序，但不会自动排序
type User struct {
	UserId              string `json:"userId"`			//用户Id
	UserName            string `json:"userName"`	    //用户名
	TimeCoin            string `json:"timeCoin"`	    //时间币数量
}

/* InitLedger 向账本添加一组基本用户 */
// ctx 是一个类型为 contractapi.TransactionContextInterface 的参数，可以在方法内部使用这个参数进行操作。  
// (s *SmartContract): 这部分是方法接收器(receiver)，它表明这是一个属于 SmartContract 结构体的方法。  
// s *SmartContract 意味着这个方法与 SmartContract 结构体的实例相关联。  
// s 是一个指向 SmartContract 类型的指针，允许在方法内部修改结构体的值
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
	// 创建一组用户  
	Users := []User{
		{UserId: "1", UserName: "blue", TimeCoin: "1000"},
		{UserId: "2", UserName: "red", TimeCoin: "1000"},
		{UserId: "3", UserName: "green", TimeCoin: "1000"},
		{UserId: "4", UserName: "yellow", TimeCoin: "1000"},
		{UserId: "5", UserName: "black", TimeCoin: "1000"},
		{UserId: "6", UserName: "white", TimeCoin: "1000"},
		{UserId: "107", UserName: "shiliuyinzhen", TimeCoin: "10000"},
		{UserId: "109", UserName: "zt", TimeCoin: "10000"},
	}

	// 将每个用户存储到账本中  
    // _ 表示我们在这个循环中不需要使用索引  
    // 如果不使用 _，就需要声明一个变量来存储迭代的索引或元素值，否则会报错。  
	for _, User := range Users {
		// 将用户转换为JSON格式
		UserJSON, err := json.Marshal(User)
		// json.Marshal() 函数是 Go 语言中的一个函数，用于将数据转换为 JSON 格式的字节切片（[]byte）。它接受一个数据结构作为参数，并尝试将其转换为 JSON 格式。  
        // 返回值包括两个部分：  
        // JSON 格式的字节切片（[]byte）：这个字节切片包含了传入数据结构的 JSON 表示形式。JSON 格式是一种轻量级的数据交换格式，通常用于在不同系统之间传递和存储数据。  
        // 错误（error）：如果转换过程中出现问题，函数会返回一个非空的错误对象。这个错误对象描述了在转换过程中发生的具体问题，例如数据结构中的字段无法被转换为 JSON 格式的情况。  
  
        // nil 是一个预定义的标识符，表示指针、切片、映射、通道、函数和接口类型的零值。  
        // 如果输出的错误不是零值，就要输出这个err
		if err != nil {
			return err
		}

		// 将JSON格式的用户存储到账本的世界状态中
		err = ctx.GetStub().PutState(User.UserId, UserJSON)
		if err != nil {
			return fmt.Errorf("向世界状态存储失败：%v", err)
		}
	}

	return nil
}
//***************************************************************************************************************************************


/* CreateUser 向世界状态添加具有给定详细信息的新用户 */
func (s *SmartContract) CreateUser(ctx contractapi.TransactionContextInterface, userId string, userName string, timeCoin string) error {
	// 检查用户是否已存在
	exists, err := s.UserExists(ctx, userId)
	if err != nil {
		return err
	}
	// 如果用户已存在，则返回错误 
	if exists {
		return fmt.Errorf("用户 %s 已经存在", userId)
	}

	// 创建新的用户对象 
	User := User{
		UserId:              userId,
		UserName:          userName,
		TimeCoin:  		   timeCoin,
	}
	// 将用户转换为JSON格式
	UserJSON, err := json.Marshal(User)
	if err != nil {
		return err
	}

	// 将JSON格式的用户存储到世界状态中
	return ctx.GetStub().PutState(userId, UserJSON)
}
//***************************************************************************************************************************************


/* ReadUser 返回世界状态中具有给定ID的用户 */
func (s *SmartContract) ReadUser(ctx contractapi.TransactionContextInterface, userId string) (*User, error) {
	// 根据Id查询用户
	UserJSON, err := ctx.GetStub().GetState(userId)

	if err != nil {
		return nil, fmt.Errorf("从世界状态读取失败: %v", err)
	}

	// 如果用户Id不存在
	if UserJSON == nil {
		return nil, fmt.Errorf("用户Id: %s 不存在", userId)
	}

	// 将为JSON格式格式数据转换为用户对象
	var User User
	err = json.Unmarshal(UserJSON, &User)
	if err != nil {
		return nil, err
	}

	return &User, nil
}
//***************************************************************************************************************************************


/*  UpdateUser 根据提供的参数更新世界状态中的现有用户 */
func (s *SmartContract) UpdateUser(ctx contractapi.TransactionContextInterface, userId string, userName string, timeCoin string) error {
	// 检查用户是否存在
	exists, err := s.UserExists(ctx, userId)
	if err != nil {
		return err
	}

	// 如果用户不存在，则返回错误
	if !exists {
		return fmt.Errorf("用户id: %s 不存在", userId)
	}

	// 创建新的用户对象，用提供的参数覆盖原始用户信息
	User := User{
		UserId:               userId,
		UserName:           userName,
		TimeCoin: 			timeCoin,		
	}

	//将新的用户信息转换为JSON格式
	UserJSON, err := json.Marshal(User)
	if err != nil {
		return err
	}

	// 将更新后的用户信息存储到世界状态中，覆盖原始用户信息
	return ctx.GetStub().PutState(userId, UserJSON)
}
//***************************************************************************************************************************************

/* DeleteIdentity 从世界状态中删除指定的用户 */
func (s *SmartContract) DeleteUser(ctx contractapi.TransactionContextInterface, userId string) error {
	// 检查要删除的用户是否存在于世界状态中
	exists, err := s.UserExists(ctx, userId)
	if err != nil {
		return err
	}

	// 如果用户不存在，则返回错误
	if !exists {
		return fmt.Errorf("用户id: %s 不存在", userId)
	}

	// 从世界状态中删除指定ID的用户信息
	return ctx.GetStub().DelState(userId)
}
//***************************************************************************************************************************************


/* UserExists 当世界状态中存在具有指定ID的用户时返回 true */
func (s *SmartContract) UserExists(ctx contractapi.TransactionContextInterface, userId string) (bool, error) {
	// 从世界状态获取指定ID的用户信息
	UserJSON, err := ctx.GetStub().GetState(userId)
	if err != nil {
		return false, fmt.Errorf("从世界状态读取失败： %v", err)
	}

	// 检查用户信息是否为空，若不为空则用户存在，返回 true；否则返回 false
	return UserJSON != nil, nil
}
//***************************************************************************************************************************************

// /* TransferUser 更新世界状态中具有给定ID的用户的所有者字段，并返回旧的所有者 */
// func (s *SmartContract) TransferUser(ctx contractapi.TransactionContextInterface, userId int, newstring) error {
// 	User, err := s.ReadUser(ctx, UserId)
// 	if err != nil {
// 		return err
// 	}

// 	User.= newOwner
// 	UserJSON, err := json.Marshal(User)
// 	if err != nil {
// 		return err
// 	}

// 	return ctx.GetStub().PutState(UserId, UserJSON)
// }

/* GetAllUsers 返回世界状态中找到的所有用户 */
func (s *SmartContract) GetAllUsers(ctx contractapi.TransactionContextInterface) ([]*User, error) {
	// 使用空字符串作为startKey和endKey进行范围查询，
	// 可以查询链码命名空间中的所有用户。
	resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	// 遍历查询结果
	var Users []*User
	for resultsIterator.HasNext() {
		// 获取下一个用户的信息
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}

		// 解析用户信息为User结构体
		var User User
		err = json.Unmarshal(queryResponse.Value, &User)
		if err != nil {
			return nil, err
		}
		// 将用户信息添加到用户列表中
		Users = append(Users, &User)
	}

	return Users, nil
}
